import { defineStore } from 'pinia';
import { getToken, removeToken, setToken } from '../utils/token-utils';
import type { UserInfoState } from './interface';
import { ElMessage } from 'element-plus';
import { staticRoutes, allAsyncRoutes, anyRoute } from '@/router/routes';
import { reqLogin, reqLogout, reqUserInfo } from '@/api/user';
import type { RouteRecordRaw } from 'vue-router';
import router from '../router';
import { cloneDeep } from 'lodash'; // 按需引入
// vue2与vue3最大的代码模式改变就是从对象式转换成了函数式，从整体引入转向按需引入
// treeshaking

// allAsyncRoutes是路由的数组类型，所以是RouteRecordRaw[]
// routeNames是字符串类型，所以是string[]
function filterAsyncRoutes(
    allAsyncRoutes: RouteRecordRaw[],
    routeNames: string[]
) {
    return allAsyncRoutes.filter((route) => {
        // 将路由中name属性与routeNames中的字符串进行比较，如果相同，则返回true
        if (routeNames.indexOf(route.name as string) === -1) {
            return false;
        }

        // 因为还存在子路由，所以需要递归调用
        // 递归的操作原则是：函数中调用自身函数，但是需要有退出条件
        if (route.children && route.children.length > 0) {
            route.children = filterAsyncRoutes(route.children, routeNames);
        }
        return true;
    });
}

function addRoutes(routes: RouteRecordRaw[]) {
    // router里原来就已经有了staticRoutes也就是静态路由，所以我只需要将动态和任意追加上去就可以了
    routes.forEach((route) => {
        // 在原来的路由中，动态的将每一个新的路由配置项进行动态的添加
        router.addRoute(route);
    });
}
/**
 * 用户信息
 * @methods setUserInfos 设置用户信息
 */
export const useUserInfoStore = defineStore('userInfo', {
    state: (): UserInfoState => ({
        token: getToken() as string,
        userInfo: {
            routes: [],
            buttons: [],
            roles: [],
            name: '',
            avatar: '',
        },
        menuRoutes: staticRoutes,
    }),

    actions: {
        async login(username: string, password: string) {
            //login是一个异步函数,将来调用这个函数的时候,会确认是否成功,所以默认login返回成功promise,如果在login中发生失败,则应该返回失败的promise
            try {
                const result = await reqLogin({ username, password });
                // console.log(result, 111);

                //设置token本地存储
                setToken(result.token);
                //把token放在state中
                this.token = result.token;
            } catch (e) {
                return Promise.reject(e);
            }
        },

        async getInfo() {
            try {
                const result = await reqUserInfo();
                this.userInfo = result;

                // 现在有menuRoutes、allAsyncRoutes、anyRoute
                // 因为allAsyncRoutes中有children嵌套路由的问题，所以需要递归操作

                const arrRoutes = this.userInfo.routes.map((route) => {
                    return route.toLocaleLowerCase();
                });

                const asyncRoutes = filterAsyncRoutes(
                    cloneDeep(allAsyncRoutes),
                    arrRoutes
                );

                // @ 以admin用户为登录前提：最终的异步路由有5个
                // @ 以trademark03用户为登录前提：最终的异步路由应该有2个，但事实上并没有任何改变
                // ! 思考：为什么路由菜单的内容没有任何的变化，这是因为allAsyncRoutes对象没有发生任何改变

                console.log('asyncRoutes', asyncRoutes);
                // 将静态路由、动态路由、任意路由重新拼接
                // ! 现在仅仅实现的是菜单显示还是不显示的工作，路由的跳转并没有实现
                this.menuRoutes = [...staticRoutes, ...asyncRoutes, anyRoute];

                // 我们完整的能够实现路由跳转的路由并没有生成
                // ! 下面实现的是路由的跳转
                addRoutes([...asyncRoutes, anyRoute]);

                console.log(this.userInfo.buttons);
            } catch (e) {
                return Promise.reject(e);
            }
        },

        async logout() {
            try {
                //发送退出登录请求
                await reqLogout();
                //调用自己封装的reset方法
                this.reset();
            } catch (e) {
                return Promise.reject(e);
            }
        },

        reset() {
            // 删除local中保存的token
            removeToken();
            // 提交重置用户信息的mutation
            this.token = '';
            //清空userInfo
            this.userInfo = {
                routes: [],
                buttons: [],
                roles: [],
                name: '',
                avatar: '',
            };
        },
    },
});
